package com.ruoyi.project.erp.service.impl;

import cn.hutool.extra.pinyin.PinyinUtil;
import com.alibaba.fastjson2.JSON;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.DingConfig;
import com.ruoyi.project.erp.service.IDingTalkService;
import com.ruoyi.project.system.domain.*;
import com.ruoyi.project.system.mapper.*;
import com.ruoyi.project.system.service.ISysDeptService;
import com.ruoyi.project.system.service.ISysUserService;
import com.ruoyi.project.tool.DingSDK;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DingTalkServiceImpl implements IDingTalkService {

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private SysDeptMapper deptMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysPostMapper postMapper;

    @Autowired
    private ISysUserService userService;

    /**
     * 获取钉钉Token
     *
     * @return 钉钉Token
     */
    @Override
    public String getToken() {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest req = new OapiGettokenRequest();
            req.setAppkey("dingxbvb4gweadq865ac");
            req.setAppsecret("YlxPX4-38XlciYtTGsl0KM710o8cz7QUK6Gs9sQ_7Nk-l17cc5st9AEoAHHPNLA6");
            req.setHttpMethod("GET");
            OapiGettokenResponse rsp = client.execute(req);
            return rsp.getAccessToken();
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return "";
    }



    @Override
    public String getAccessToken() throws Exception {

        com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest getAccessTokenRequest = new com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest()
                .setAppKey(DingConfig.clientID)
                .setAppSecret(DingConfig.ClientSecret);
        GetAccessTokenResponse getAccessTokenResponse = DingSDK.createClient().getAccessToken(getAccessTokenRequest);
        return getAccessTokenResponse.getBody().getAccessToken();
    }




    public OapiV2DepartmentGetResponse queryDeptInfo(Long deptId) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get");
            OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest();
            req.setDeptId(deptId); // 设置部门ID
            OapiV2DepartmentGetResponse rsp = client.execute(req, getToken());
            return rsp;
        } catch (ApiException e) {
            e.printStackTrace();
        }
        return new OapiV2DepartmentGetResponse();
    }

    @Override
    public void syncListDept() {
        SysDept dept = new SysDept();
        try {
            // 获取部门信息
            OapiV2DepartmentGetResponse rspInfo = queryDeptInfo(1L);

            dept.setDeptId(rspInfo.getResult().getDeptId());
            dept.setParentId(0L); // 根部门的父ID为0
            dept.setAncestors("0");
            dept.setDeptName(rspInfo.getResult().getName());
            dept.setOrderNum(Math.toIntExact(rspInfo.getResult().getOrder()));
            dept.setStatus("0");
            sysDeptService.insertDept(dept);
            // 获取子部门ID列表
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsubid");
            OapiV2DepartmentListsubidRequest req = new OapiV2DepartmentListsubidRequest();
            req.setDeptId(1L); // 设置部门ID
            OapiV2DepartmentListsubidResponse rsp = client.execute(req, getToken());

            ObjectMapper mapper = new ObjectMapper();
            JsonNode rootNode = mapper.readTree(rsp.getBody());
            System.out.println("dept_id_list:");
            for (JsonNode idNode : rootNode.path("result").path("dept_id_list")) {
                System.out.println(idNode.asLong());
                OapiV2DepartmentGetResponse response = queryDeptInfo(idNode.asLong());
                dept.setDeptId(response.getResult().getDeptId());
                dept.setParentId(response.getResult().getParentId());
                dept.setAncestors(response.getResult().getParentId().toString());
                dept.setDeptName(response.getResult().getName());
                dept.setOrderNum(Math.toIntExact(response.getResult().getOrder()));
                sysDeptService.insertDept(dept);
            }
            System.out.println(rsp.getBody());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void syncListUser() {
        List<SysDept> depts = sysDeptService.selectDeptList(new SysDept());
        depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()).forEach(deptsId -> {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
            OapiUserListidRequest req = new OapiUserListidRequest();
            req.setDeptId(deptsId);
            OapiUserListidResponse rsp = null;
            try {
                rsp = client.execute(req, getToken());
                if (rsp.getResult().getUseridList() != null || rsp.getResult().getUseridList().size() != 0) {
                    rsp.getResult().getUseridList().forEach(x -> {
                        System.out.println("x-------------------------> = " + x);
                        if (x.equals("0845585759-891867131"))
                            return;
                        DingTalkClient client1 = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
                        OapiV2UserGetRequest request = new OapiV2UserGetRequest();
                        request.setUserid(x);
                        OapiV2UserGetResponse response = null;
                        try {
                            response = client1.execute(request, getToken());
                            System.out.println(response.getBody());
                            SysUser user = new SysUser();
                            user.setDdUserId(x);
                            user.setDeptId(response.getResult().getDeptIdList().get(0));
                            user.setNickName(response.getResult().getName());
                            user.setUserName(response.getResult().getEmail() != null
                                    && response.getResult().getEmail() != ""  ? response.getResult().getEmail().split("@")[0] : response.getResult().getUnionid());
                            user.setEmail(response.getResult().getEmail());
                            user.setPhonenumber(response.getResult().getMobile());
                            user.setSex("2");
                            user.setPassword(SecurityUtils.encryptPassword("1q2w3e$R"));
                            user.setStatus("0");
                            List<SysRole> roles = new ArrayList<SysRole>();
                            // 处理角色
                            if (response.getResult().getRoleList() != null && response.getResult().getRoleList().size() > 0) {
                                response.getResult().getRoleList().stream().map(o -> {
                                    if (o.getGroupName().equals("默认")) {
                                        roles.add(roleMapper.selectRoleById(o.getId()));
                                    }
                                    return null;
                                });
                            } else {
                                SysRole defaultRole = roleMapper.selectRoleById(2L);
                                if (defaultRole != null) {
                                    roles.add(defaultRole);
                                }
                            }

                            user.setRoles(roles);
                            user.setRoleIds(roles.stream().map(SysRole::getRoleId).toArray(Long[]::new));
                            OapiV2UserGetResponse finalResponse = response;
                            // 处理岗位
                            if (finalResponse.getResult().getTitle() != null && !finalResponse.getResult().getTitle().isEmpty()) {
                                // 查找岗位
                            SysPost post = postMapper.selectPostAll()
                                    .stream()
                                    .filter(p -> finalResponse.getResult().getTitle().equals(p.getPostName()))
                                    .findFirst()
                                    .orElse(null);

                                user.setPostIds(post != null && post.getPostId() != null? new Long[]{post.getPostId()} : new Long[]{1327731793L}); // 1327731793L 是默认岗位ID
                            } else {
                                user.setPostIds(new Long[]{1327731793L});
                            }


                            userService.insertUser(user);
                        } catch (ApiException e) {
                            throw new RuntimeException(e);
                        }
                    });
                }
                System.out.println(rsp.getBody());
            } catch (ApiException e) {
                throw new RuntimeException(e);
            }
        });

    }

    @Override
    public void syncListRolePost() {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/role/list");
            OapiRoleListRequest req = new OapiRoleListRequest();
            OapiRoleListResponse rsp = client.execute(req, getToken());
            rsp.getResult().getList().forEach(role -> {
                // 处理每个角色
                if (role.getName().equals("默认")) {
                    role.getRoles().forEach(role1 -> {
                        SysRole r = new SysRole();
                        r.setRoleId(role1.getId());
                        r.setRoleName(role1.getName());
                        r.setRoleKey("common");
                        roleMapper.insertRole(r);
                    });
                }
                if (role.getName().equals("岗位")) {
                    role.getRoles().forEach(role1 -> {
                        SysPost post = new SysPost();
                        post.setPostId(role1.getId());
                        post.setPostCode(role1.getName());
                        post.setPostName(role1.getName());
                        int i = 1;
                        post.setPostSort(i++);
                        post.setStatus("0");
                        postMapper.insertPost(post);
                    });
                }
            });
            System.out.println(rsp.getBody());
        } catch (ApiException e) {
            e.printStackTrace();
        }
    }










    @Override
    @Scheduled(cron = "0 43 5 * * ?") // 建议修改为服务器负载较低的时间，例如 "0 0 2 * * ?" 凌晨2点
    @Transactional(rollbackFor = Exception.class) // 使用 Exception.class 范围更广
    public void getUserDept() throws Exception {
        String accessToken = getAccessToken();

        // ================== 部门同步部分（保持不变） ==================
        List<SysDept> allDepts = new ArrayList<>();
        Map<Long, SysDept> deptMap = new HashMap<>();

        // 1. 递归获取所有部门
        fetchDeptRecursivelyWithDetail(1L, accessToken, allDepts, deptMap);

        log.info("插入/更新最新部门数据...");
        if (!allDepts.isEmpty()) { // 增加非空判断
            deptMapper.batchInsertOrUpdate(allDepts);
        }

        // 2. 删除本地数据库中被钉钉删掉的部门
        Set<Long> remoteDeptIds = allDepts.stream().map(SysDept::getDeptId).collect(Collectors.toSet());
        List<Long> localDeptIds = deptMapper.selectAllDeptIds();
        localDeptIds.stream()
                .filter(deptId -> !remoteDeptIds.contains(deptId) && !deptId.equals(1L))
                .forEach(deptId -> {
                    deptMapper.deleteByDeptId(deptId);
                    log.info("本地部门已被钉钉删除，已同步删除：deptId={}", deptId);
                });

        log.info("部门同步完毕，开始同步成员...");

        // ================== 成员同步部分（核心修改区域） ==================

        // 3. 拉取所有钉钉成员到一个集合中，先不处理数据库
        Set<String> remoteDdUserIds = new HashSet<>();
        // 使用一个 Map 来存储钉钉用户和其所属部门ID，避免信息丢失
        Map<String, OapiV2UserListResponse.ListUserResponse> dingTalkUserMap = new HashMap<>();
        Map<String, Long> userDeptMap = new HashMap<>();

        for (SysDept dept : allDepts) {
            List<OapiV2UserListResponse.ListUserResponse> users = getDeptUsers(dept.getDeptId(), accessToken);
            log.info("部门 {}({}) 下用户数：{}", dept.getDeptName(), dept.getDeptId(), users.size());
            for (OapiV2UserListResponse.ListUserResponse user : users) {
                // 同一个用户可能在多个部门，这里只记录他被遍历到的其中一个部门
                if (!dingTalkUserMap.containsKey(user.getUserid())) {
                    dingTalkUserMap.put(user.getUserid(), user);
                    userDeptMap.put(user.getUserid(), dept.getDeptId());
                }
                remoteDdUserIds.add(user.getUserid());
            }
        }
        // 也同步根部门下的用户（若依框架通常有这个需求）
        List<OapiV2UserListResponse.ListUserResponse> rootUsers = getDeptUsers(1L, accessToken);
        for (OapiV2UserListResponse.ListUserResponse user : rootUsers) {
            if (!dingTalkUserMap.containsKey(user.getUserid())) {
                dingTalkUserMap.put(user.getUserid(), user);
                userDeptMap.put(user.getUserid(), 1L);
            }
            remoteDdUserIds.add(user.getUserid());
        }

        // 4.  【核心改动】遍历钉钉用户，执行 "先查询，再更新或插入" 逻辑
        List<SysUser> processedUsers = new ArrayList<>(); // 用于后续角色处理
        for(OapiV2UserListResponse.ListUserResponse dingTalkUser : dingTalkUserMap.values()) {
            SysUser localUser = userMapper.selectUserByDdUserId(dingTalkUser.getUserid());
            Long deptId = userDeptMap.get(dingTalkUser.getUserid());

            if (localUser != null) { // 用户已存在 -> 更新
                // 在从数据库查出的现有对象上修改信息，密码等字段得以保留
                localUser.setNickName(dingTalkUser.getName());
                localUser.setDeptId(deptId);
                localUser.setPhonenumber(dingTalkUser.getMobile());
                localUser.setEmail(dingTalkUser.getEmail());
                localUser.setAvatar(dingTalkUser.getAvatar());
                // 根据你的逻辑更新userName
                if("魏晓茜".equals(dingTalkUser.getName())){
                    localUser.setUserName("weixiaoxi");
                } else {
                    localUser.setUserName(PinyinUtil.getPinyin(dingTalkUser.getName(),""));
                }
                localUser.setUpdateBy("system_sync"); // 设置更新者
                userMapper.updateUser(localUser); // 调用若依的 updateUser
                processedUsers.add(localUser);
            } else { // 用户不存在 -> 新增
                SysUser newUser = new SysUser();
                // 设置从钉钉获取的基础信息
                newUser.setDdUserId(dingTalkUser.getUserid());
                newUser.setDeptId(deptId);
                newUser.setNickName(dingTalkUser.getName());
                newUser.setPhonenumber(dingTalkUser.getMobile());
                newUser.setEmail(dingTalkUser.getEmail());
                newUser.setAvatar(dingTalkUser.getAvatar());
                if("魏晓茜".equals(dingTalkUser.getName())){
                    newUser.setUserName("weixiaoxi");
                } else {
                    newUser.setUserName(PinyinUtil.getPinyin(dingTalkUser.getName(),""));
                }

                // 【关键】为新用户设置默认密码和其他必要信息
                // 建议将默认密码配置在系统参数中
                newUser.setPassword(SecurityUtils.encryptPassword("123456")); // 使用若依的工具类加密
                newUser.setCreateBy("system_sync"); // 设置创建者

                userMapper.insertUser(newUser); // 调用若依的 insertUser
                // 重新查询一次以获取完整的user_id，用于后续角色关联
                processedUsers.add(userMapper.selectUserByDdUserId(newUser.getDdUserId()));
            }
        }

        // 5. 【角色同步】使用处理过的用户列表 processedUsers 进行角色同步
        processedUsers.forEach(sysUser -> {
            // 这里 sysUser 是包含正确 userId 的对象
            DingTalkClient userDetailClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
            OapiV2UserGetRequest userReq = new OapiV2UserGetRequest();
            userReq.setUserid(sysUser.getDdUserId());
            try {
                OapiV2UserGetResponse userResp = userDetailClient.execute(userReq, accessToken);
                if (userResp.isSuccess() && userResp.getResult() != null && userResp.getResult().getRoleList() != null) {
                    // ... 原有的角色判断和部门负责人设置逻辑 ...
                    userResp.getResult().getRoleList().forEach(x -> {
                        if ("主管".equals(x.getName())) {
                            Long roleId = 1327731780L; // 建议配置化
                            SysDept sysDept = deptMapper.selectDeptById(sysUser.getDeptId());
                            if (sysDept != null && StringUtils.isNull(sysDept.getLeader())) {
                                sysDept.setLeader(sysUser.getDdUserId());
                                deptMapper.updateDept(sysDept);
                            }
                            if (sysUserRoleMapper.countByUserIdAndRoleId(sysUser.getUserId(), roleId) == 0) {
                                SysUserRole sysUserRole = new SysUserRole(sysUser.getUserId(), roleId);
                                sysUserRoleMapper.insert(sysUserRole);
                            }
                        }
                        if ("负责人".equals(x.getName())) {
                            Long roleId = 1327731779L; // 建议配置化
                            if (sysUserRoleMapper.countByUserIdAndRoleId(sysUser.getUserId(), roleId) == 0) {
                                SysUserRole sysUserRole = new SysUserRole(sysUser.getUserId(), roleId);
                                sysUserRoleMapper.insert(sysUserRole);
                            }
                        }
                    });
                }
                // 确保每个用户至少有一个默认角色
                List<SysUserRole> userRoles = sysUserRoleMapper.selectByUserId(sysUser.getUserId());
                if (ObjectUtils.isEmpty(userRoles)) {
                    SysUserRole defaultRole = new SysUserRole(sysUser.getUserId(), 2L); // 2L-普通角色
                    sysUserRoleMapper.insert(defaultRole);
                }
            } catch (ApiException e) {
                // 建议更详细的日志记录
                log.error("Failed to sync roles for user: {}", sysUser.getUserName(), e);
                throw new RuntimeException(e); // 事务会回滚
            }
        });

        // 6. 【删除用户】删除本地数据库中被钉钉删掉的成员
        // 注意这里 selectAllUserIds() 应该返回 dd_user_id 列表，如果不是请修改mapper
        List<String> localDdUserIds = userMapper.selectAllDdUserIds();
        localDdUserIds.stream()
                .filter(ddUserId -> !remoteDdUserIds.contains(ddUserId))
                .forEach(ddUserId -> {
                    userMapper.deleteUserByDdUserId(ddUserId); // 建议按 dd_user_id 删除
                    log.info("本地成员已被钉钉删除，已同步删除：dd_user_id={}", ddUserId);
                });

        log.info("钉钉组织架构和成员同步完毕。");
    }

    /**
     * 递归抓取所有部门，拉详情以补齐 order 字段
     */
    private void fetchDeptRecursivelyWithDetail(Long parentDeptId, String accessToken, List<SysDept> result, Map<Long, SysDept> cache) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
        OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
        req.setDeptId(parentDeptId);

        OapiV2DepartmentListsubResponse rsp = client.execute(req, accessToken);
        if (!rsp.isSuccess() || rsp.getResult() == null) {
            return;
        }
        for (OapiV2DepartmentListsubResponse.DeptBaseResponse deptInfo : rsp.getResult()) {
            // 获取详细信息，包括 order
            SysDept sysDept = fetchOneDeptDetail(deptInfo.getDeptId(), accessToken);
            result.add(sysDept);
            cache.put(sysDept.getDeptId(), sysDept);
            // 递归处理子部门
            fetchDeptRecursivelyWithDetail(sysDept.getDeptId(), accessToken, result, cache);
        }
    }

    /**
     * 获取单个部门完整详情，含 order
     */
    private SysDept fetchOneDeptDetail(Long deptId, String accessToken) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get");
        OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest();
        req.setDeptId(deptId);
        OapiV2DepartmentGetResponse rsp = client.execute(req, accessToken);

        SysDept dept = new SysDept();
        if (rsp.isSuccess() && rsp.getResult() != null) {
            OapiV2DepartmentGetResponse.DeptGetResponse info = rsp.getResult();
            dept.setDeptId(info.getDeptId());
            dept.setDeptName(info.getName());
            dept.setParentId(info.getParentId());
            dept.setOrderNum(info.getOrder() != null ? info.getOrder().intValue() : 0);
        } else {
            dept.setDeptId(deptId); // 可选，异常容错
        }
        return dept;
    }

    /**
     * 分页获取指定部门下所有成员详细信息
     */
    private List<OapiV2UserListResponse.ListUserResponse> getDeptUsers(Long deptId, String accessToken) throws ApiException {
        List<OapiV2UserListResponse.ListUserResponse> allUsers = new ArrayList<>();
        Long cursor = 0L;
        Long size = 100L;
        boolean hasMore = true;

        while (hasMore) {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
            OapiV2UserListRequest req = new OapiV2UserListRequest();
            req.setDeptId(deptId);
            req.setCursor(cursor);
            req.setSize(size);

            OapiV2UserListResponse rsp = client.execute(req, accessToken);
            OapiV2UserListResponse.PageResult result= rsp.getResult();
            if (result != null && result.getList() != null) {
                allUsers.addAll(result.getList());
            }
            hasMore = result != null && Boolean.TRUE.equals(result.getHasMore());
            if (hasMore && result != null && result.getNextCursor() != null) {
                cursor = result.getNextCursor();
            } else {
                hasMore = false;
            }
        }
        return allUsers;
    }

    /**
     * 成员结构转换
     */
    private SysUser convertUser(OapiV2UserListResponse.ListUserResponse user, Long deptId) {
        SysUser sysUser = new SysUser();
        sysUser.setDdUserId(user.getUserid());
        if("魏晓茜".equals(user.getName())){
            sysUser.setUserName("weixiaoxi");
        }else{
            sysUser.setUserName(PinyinUtil.getPinyin(user.getName(),""));
        }
        sysUser.setNickName(user.getName());
        sysUser.setDeptId(deptId);
        sysUser.setPhonenumber(user.getMobile());
        sysUser.setEmail(user.getEmail());
        sysUser.setEmail(user.getEmail());
        sysUser.setAvatar(user.getAvatar());
        return sysUser;
    }
}
